package ch.subgate.pongwars;

public class GameContext {
    /** View surface width */
    public float surfaceWidth = 1.0f;

    /** View surface height */
    public float surfaceHeight = 1.0f;

    /** 4 by 3 arena width in pixels */
    public float battlefieldWidth;

    /** 4 by 3 arena height in pixels */
    public float battlefieldHeight;

    /** 4 by 3 arena top position */
    public float battlefieldTop;

    /** 4 by 3 arena left position */
    public float battlefieldLeft;

    /** 1 device independent arena unit in pixels */
    public float unitWidth;

    /** TimeOut is used to pause the game */
    public float timeOut;

    /** Message string */
    public String mMsg;

    /*
     * ---- Game objects ----
	 */

    public Player playerRed;

    public Player playerBlue;

    public Ball ball;

    /**
     * Initialize GameContext object. Calling this method will not instantiate the associated GameObjects
     * but will simply initialize all the metric data for simulating and drawing the battlefield.
     * @param width The devices screen width in pixels
     * @param height The devices screen height in pixels
     */
    public void initMetrics(int width, int height) {
        surfaceWidth = (float)width;
        surfaceHeight = (float)height;

        float refWidth = surfaceWidth - Constants.BATTLEFIELD_MARGIN;
        float refHeight = surfaceHeight - Constants.BATTLEFIELD_MARGIN;

        if (refHeight / 4.0f * 3.0f > refWidth) {
            battlefieldWidth = refWidth;
            battlefieldHeight = refWidth / 3.0f * 4.0f;
        } else {
            battlefieldHeight = refHeight;
            battlefieldWidth = refHeight / 4.0f * 3.0f;
        }

        battlefieldTop = (surfaceHeight - battlefieldHeight) / 2.0f;
        battlefieldLeft = (surfaceWidth - battlefieldWidth) / 2.0f;

        unitWidth = battlefieldWidth / Constants.DIC_BATTLEFIELD_WIDTH;

        timeOut = Constants.TIME_TIMEOUT;

        mMsg = Constants.READY_TEXT;

    } // initMetrics

    /**
     * Initialize the game objects. Any instance of GameContext must call initMetrics and initGameObjects
     * first in order to be used.
     * @param mode The game mode determines who is playing against who, see the associated constants for more info
     * @param paddleSize The paddle size used for this match
     * @param isServer If this is a network game, we need to know if this is the server or client side
     */
    public void initGameObjects(int mode, float paddleSize, boolean isServer) {
        // Instantiate game objects
        ball = new Ball(Constants.DIRECTION_BLUE_BEGINS);
        switch (mode) {
            case Constants.MODE_PVE:
                playerRed = new AIPlayer(true, paddleSize);
                playerBlue = new HumanPlayer(false, paddleSize);
                ((AIPlayer)playerRed).setBall(ball);
                break;
            case Constants.MODE_PVP:
                playerRed = new HumanPlayer(true, paddleSize);
                playerBlue = new HumanPlayer(false, paddleSize);
                break;
            case Constants.MODE_PVPN:
                if (isServer) {
                    playerRed = new NetworkPlayer(true, paddleSize);
                    playerBlue = new HumanPlayer(false, paddleSize);
                } else {
                    playerRed = new HumanPlayer(true, paddleSize);
                    playerBlue = new NetworkPlayer(false, paddleSize);
                } // if
                break;
        } // switch
    } // initGameObjects

    /**
     * This method is called by the game loop thread. It's responsibility is to call the different
     * update() - methods of the simulated GameObjects.
     * @param deltaTime The time passed since the last iteration in seconds
     */
    public void update(float deltaTime) {
        if (timeOut > 0.0f) {
            timeOut -= deltaTime;
        } else {
            ball.update(deltaTime);
            playerRed.update(deltaTime);
            playerBlue.update(deltaTime);
            GameHelper.applyBounce(ball, playerRed, playerBlue);
        } // if
    } // update

    /**
     * Returns negative result if the red player has a match ball, positive if the blue player has
     * a match point and 0 if the game is currently drawn or the leading player has a score < 2
     * @return -1 if red has match ball, 1 for blue and 0 for no player having match ball
     */
    public int checkMatchBall() {
        if ((playerRed.mPoints > playerBlue.mPoints) && (playerRed.mPoints > 1)) { return -1; }
        else if ((playerBlue.mPoints > playerRed.mPoints) && (playerBlue.mPoints > 1)) { return 1; }
        else { return 0; }
    } // checkMatchBall

    public void checkGoals() {
        if (ball.mY > Constants.DIC_BATTLEFIELD_HEIGHT) {
            // Ball is colliding with battlefield bottom
            playerRed.mPoints++;
            playerRed.reset();
            playerBlue.reset();
            ball.reset(Constants.DIRECTION_BLUE_BEGINS);
            timeOut = Constants.TIME_TIMEOUT;
            mMsg = Constants.READY_TEXT;
        } else if (ball.mY < 0.0f) {
            // Ball is colliding with battlefield top
            playerBlue.mPoints++;
            playerRed.reset();
            playerBlue.reset();
            ball.reset(Constants.DIRECTION_RED_BEGINS);
            timeOut = Constants.TIME_TIMEOUT;
            mMsg = Constants.READY_TEXT;
        } // if
    } // checkGoals

    public void checkWin() {
        if (
                ((playerRed.mPoints >= 3) && (playerRed.mPoints - playerBlue.mPoints >= 2))
                || ((playerBlue.mPoints >= 3) && (playerBlue.mPoints - playerRed.mPoints >= 2))) {
            timeOut = Constants.TIME_TIMEOUT;
            if (playerRed.mPoints > playerBlue.mPoints) {
                ball.reset(Constants.DIRECTION_BLUE_BEGINS);
                mMsg = Constants.RED_WIN_TEXT;
            } else {
                ball.reset(Constants.DIRECTION_RED_BEGINS);
                mMsg = Constants.BLUE_WIN_TEXT;
            } // if
            playerRed.mPoints = 0;
            playerBlue.mPoints = 0;
        } // if
    } // checkWin

} // GameContext
